package com.xuecheng.base.config;

import cn.hutool.core.util.StrUtil;
import com.xuecheng.base.util.AESUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.*;

import java.util.HashMap;
import java.util.Map;

public class DecryptEnvironmentPostProcessor implements EnvironmentPostProcessor {

    /**
     * 加密配置属性值前缀
     */
    private static final String ENC_PREFIX = "ENC(";

    /**
     * 加密配置属性值后缀
     */
    private static final String ENC_SUFFIX = ")";

    /**
     * 处理配置属性值
     *
     * @param environment           环境
     * @param application           应用程序
     */
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        // 获取配置属性源
        MutablePropertySources propertySources = environment.getPropertySources();
        // 存放解密后的属性
        Map<String, Object> decryptedProperties = new HashMap<>();
        // 遍历配置属性源并处理
        for (PropertySource<?> propertySource : propertySources) {
            if (propertySource instanceof EnumerablePropertySource<?>) {
                // 处理配置属性源，将加密的配置属性值解密后加到decryptedProperties中
                processPropertySource((EnumerablePropertySource<?>) propertySource, environment, decryptedProperties);
            }
        }
        // 添加解密后的属性到环境中，优先级最高
        if (!decryptedProperties.isEmpty()) {
            propertySources.addFirst(new MapPropertySource("decryptedProperties", decryptedProperties));
        }
    }

    /**
     * 处理配置属性源
     *
     * @param propertySource    配置属性源
     * @param environment       环境
     * @param decryptedProperties 解密后的属性
     */
    @SuppressWarnings("all")
    private void processPropertySource(EnumerablePropertySource<?> propertySource, ConfigurableEnvironment environment, Map<String, Object> decryptedProperties) {
        String[] propertyNames = propertySource.getPropertyNames();
        for (String propertyName : propertyNames) {
            String propertyValue = environment.getProperty(propertyName);
            if (isEncryptedValue(propertyValue)) {
                try {
                    String decryptedValue = decryptPropertyValue(propertyValue);
                    decryptedProperties.put(propertyName, decryptedValue);
                } catch (Exception e) {
                    // 记录解密失败的日志，但继续处理其他属性
                    System.err.println("Failed to decrypt property: " + propertyName + ". Error: " + e.getMessage());
                }
            }
        }
    }

    /**
     * 判断属性值是否为加密值
     *
     * @param value 属性值
     * @return true表示为加密值，false表示不是加密值
     */
    private boolean isEncryptedValue(String value) {
        return StrUtil.isNotBlank(value) && value.startsWith(ENC_PREFIX) && value.endsWith(ENC_SUFFIX);
    }

    /**
     * 解密属性值
     *
     * @param encryptedValue 加密后的属性值
     * @return 解密后的属性值
     */
    private String decryptPropertyValue(String encryptedValue) {
        // 去除前后缀
        String encryptedContent = encryptedValue.substring(ENC_PREFIX.length(), encryptedValue.length() - ENC_SUFFIX.length());
        // 调用自定义工具类解密
        return AESUtil.decrypt(encryptedContent);
    }
}